package com.ek.kademlia.handlers;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ek.common.AbstractMessageHandler;
import com.ek.common.Bucket;
import com.ek.common.Context;
import com.ek.kademlia.DefaultBucket;
import com.ek.kademlia.protocol.FindNodeRequest;
import com.ek.kademlia.protocol.Message;
import com.ek.kademlia.protocol.impl.DefaultFindNodeResponse;
import com.ek.service.mina.ComunicationService;
import com.ek.util.Utils;

public class FindNodeRequestHandler extends AbstractMessageHandler<FindNodeRequest> {
    private static final transient Logger log = LoggerFactory.getLogger(FindNodeRequestHandler.class);

    public FindNodeRequestHandler(Context context) {
        super(context);
    }

    @Override
    protected void doExecute(FindNodeRequest message, SocketAddress address) {
        log.debug("received FIND_NODE request from bucket with this socketAddress:" + address + " and this FindNodeRequest:" + message);
        LinkedList<Bucket> closestBucket = getContext().getRoutingTable().getClosestBucket(message.getQueryID(), 3);
        removeIfPresent(closestBucket, message, address);
        DefaultFindNodeResponse response = new DefaultFindNodeResponse();
        response.setMessageID(message.getMessageID());
        response.setNodeID(getContext().getNodeID());
        response.setBuckets(closestBucket);
        InetSocketAddress socketAddress = (InetSocketAddress) address;
        log.debug("sending the FIND_NODE response to bucket with this socketAddress:" + socketAddress + " and this FindNodeResponse:" + response);
        getContext().getComunicationService().sendResponse(response, new InetSocketAddress(socketAddress.getAddress(), ComunicationService.PORT));
    }

    protected void removeIfPresent(List<Bucket> buckets, Message message, SocketAddress socketAddress) {
        try {
            DefaultBucket bucket = new DefaultBucket();
            bucket.setAddress(Utils.getAddressOfSocketAddress(socketAddress));
            // TODO:now is setted but must be changed for different port
            bucket.setPort(ComunicationService.PORT);
            bucket.setNodeID(message.getNodeID());
            for (Bucket tempBucket : buckets) {
                if (tempBucket.equals(bucket)) {
                    buckets.remove(bucket);
                    log.debug("removed the bucket that have send the request, bucket:" + bucket);
                    break;
                }
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    public static String getMessageClass() {
        return FindNodeRequest.class.getCanonicalName();
    }

}
